import { h, computed, ref } from 'vue'
import type { ComputedRef, PropType, Ref } from 'vue'
import {
    Form,
    Input,
    Radio,
    FormItem,
    Checkbox,
    RadioGroup,
    CheckboxGroup,
    Switch,
    InputNumber,
    Select
} from '@arco-design/web-vue'

//去除定义类型中 指定的key
type RestrictKey<T, K extends keyof any> = {
    [P in keyof T]: P extends K ? never : T[P]
}

export type formElementType = | 'radio'
| 'input'
| 'checkbox'
| 'slot'
| 'radioGroup'
| 'checkboxGroup'
| 'switch'
| 'inputNumber'
| 'select'

//FormPropsType 类型中的属性与官网form 组件的属性保持一致 但不用再声明model属性
export type FormPropsType = RestrictKey<
    {
        model?: string
        items: {
            [key: string]: {
                type:formElementType
                    
                hidden?: boolean //是否隐藏该表单项，但是不会过滤该值
                filter?: boolean //是否通过useFormHook过滤该字段的值
                //slotFormConfig 为slot组件的modelValue
                //config 为formItem组件的属性
                //config 类型中的属性与官网formItem 组件的属性保持一致 但不用再声明field属性
                config: RestrictKey<
                    {
                        [key: string]: any
                        field?: string
                    },
                    'field'
                > //去除field属性 不允许传model属性
                slotFormConfig: {
                    modelValue: any
                    [key: string]: any
                }
            }
        }
        [key: string]: any
    },
    'model'
> //去除model属性 不允许传model属性

export default {
    components: {
        Form,
        Input,
        Radio,
        FormItem,
        Checkbox
    },
    props: {
        config: {
            type: Object as PropType<FormPropsType>
        }
    },
    setup(props: FormPropsType, { expose, emit, slots }: any) {
        const FormRef = ref()

        //渲染表单项组件
        const formItemComponent = computed(() => {
            return Array.from(Object.keys(props.config.items)).map(formItemName => {
                const formItemConfig = props.config.items[formItemName]

                if(formItemConfig.config.onClick){
                  let onClick = formItemConfig.config.onClick
                    formItemConfig.config.onClick = () => {
                      onClick(formItemConfig)
                    }
                }

                if (formItemConfig.hidden) {
                    return
                }
                formItemConfig.slotFormConfig['onUpdate:modelValue'] = (e: any) => {
                    // emit('onUpdate:modelValue', e)`
                    formItemConfig.slotFormConfig.modelValue = e
                }
                formItemConfig.config['field'] = formItemName
                let slotComp
                switch (formItemConfig.type) {
                    case 'slot':
                        slotComp = h(
                            'div',
                            {
                                style: {
                                    width: '100%',
                                    height: '100%'
                                }
                            },
                            slots[formItemName](props.config.items[formItemName].slotFormConfig)
                        )
                        break
                    case 'input':
                        slotComp = h(Input, props.config.items[formItemName].slotFormConfig)
                        break
                    case 'radio':
                        slotComp = h(Radio, props.config.items[formItemName].slotFormConfig)
                        break
                    case 'radioGroup':
                        slotComp = h(RadioGroup, props.config.items[formItemName].slotFormConfig)
                        break
                    case 'checkbox':
                        slotComp = h(Checkbox, props.config.items[formItemName].slotFormConfig)
                        break
                    case 'checkboxGroup':
                        slotComp = h(CheckboxGroup, props.config.items[formItemName].slotFormConfig)
                        break
                    case 'switch':
                        slotComp = h(Switch, props.config.items[formItemName].slotFormConfig)
                        break
                    case'inputNumber':
                        slotComp = h(InputNumber, props.config.items[formItemName].slotFormConfig)
                        break
                    case'select':
                        slotComp = h(Select, props.config.items[formItemName].slotFormConfig)
                        break
                }
                const comp = h(FormItem, formItemConfig.config, slotComp)
                return comp
            })
        })

        //渲染表单组件
        const formComponent = computed(() => {
            return h(
                Form,
                {
                    ...props.config,
                    model: Object.keys(props.config.items)
                        .map(formItemName => {
                            return [
                                formItemName,
                                props.config.items[formItemName].slotFormConfig.modelValue
                            ]
                        })
                        .reduce((acc: any, [key, value]) => {
                            acc[key] = value
                            return acc
                        }, {}),
                    ref: FormRef
                },
                formItemComponent.value
            )
        }) 

        expose({
            FormRef
        })
        return () => h('div', {}, formComponent.value)
    }
}

export function useFormHook(formConfig: Ref<FormPropsType>): [ComputedRef<{ [key: string]: any }>, (KeyVals: Array<{ key: string; value: any }>) => void] {
    let formItemValue: ComputedRef<{ [key: string]: any }> = computed(() => {
        let value: { [key: string]: any } = {}
        for (let key in formConfig.value.items) {
            if (formConfig.value.items[key].filter) {
                continue
            }
            value[key] = formConfig.value.items[key].slotFormConfig.modelValue
        }
        return value
    })

    function setFormItemValue(KeyVals: Array<{ key: string; value: any }>):void {
        KeyVals.forEach(item => {
          if(  !formConfig.value.items[item.key]) return
            formConfig.value.items[item.key].slotFormConfig.modelValue = item.value
        })
    }

    return [formItemValue,setFormItemValue]
}
